from rest_framework import status
# from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet, ViewSet, ReadOnlyModelViewSet
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import BaseAuthentication
from rest_framework_simplejwt.authentication import JWTAuthentication
import logging
import requests

from django.utils import timezone
from django.http import HttpResponse

# from tsl_backend.fgr_api.decorator import insert_fgr_bearer
# import tsl_backend.fgr_api.views.fgr_apis as fgr_apis
import tsl_backend.users.models as users
import tsl_backend.frontend_api.models.workorder as workorders
import tsl_backend.frontend_api.models.route as routes
import tsl_backend.frontend_api.models.order_routing as order_routing

import tsl_backend.frontend_api.serializers.serializers as frontend_serializers
from tsl_backend.frontend_api.middleware import response as frontend_response
# import tsl_backend.frontend_api.middleware as frontend_middleware
import tsl_backend.common as common
import tsl_backend.frontend_api.utils.lib as frontend_lib
import tsl_backend.frontend_api.utils.orderViewRecord as frontend_orderview
from django.conf import settings


class OrderView(ModelViewSet):
    queryset = workorders.Detail.objects.all()
    serializer_class = frontend_serializers.DetailSerializer

    http_method_names = ["get", "post"]
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]
    
    def get_authenticators(self) -> list[BaseAuthentication]:
        if action := self.action_map.get("get"):
            # 图片代理放开权限
            if action == "get_black_pic_img":
                return []
        return super().get_authenticators()
    
    def get_permissions(self) :
        if action := self.action_map.get("get"):
            # 图片代理放开认证
            if action == "get_black_pic_img":
                return []
        return super().get_permissions()

    def retrieve(self, request, pk=None):
        workorder = self.get_object()
        if common.check_order_discard(workorder):
            logging.info(f"Oder {workorder} is discard")
            message = "Order is discarded."
            data={}
            return frontend_response(status.HTTP_200_OK, message, data)

        detail_serializer = self.get_serializer(workorder)
        data = detail_serializer.data

        account_pk = request.GET.get("account_pk", None)
        if not account_pk:
            message = "Failed tp get account"
            return frontend_response(status.HTTP_200_OK, message, data)

        user_account_obj = users.Account.objects.get(pk=account_pk)
        logging.info(f"{user_account_obj.pk=}")
        role = user_account_obj.role
        
        # retrieve actualbom information
        # try:
        logging.info(f"Prepare actualbom")
        message, actualbom_data=frontend_orderview.get_actual_bom_fr_fgr(workorder.order, workorder.source)
        logging.info(f"Actual bom data return to frontend: {actualbom_data}")
        data["prod"]["actualBom"]["stoneInfo"] = actualbom_data
        workorder.refresh_from_db()


        # except Exception as e:
        #     logging.error(f"Exception to query actual bom from FGR: {e}")
        # try:
        #     actualboms_set = workorder.productionactualbom_set.all()
        # except Exception as e:
        #     logging.warn(f"No actualbom was found: {e}")
        # else:
        #     actualbom_data = frontend_serializers.ActualbomSerializer(
        #         instance=actualboms_set, many=True
        #     ).data
        #     data["prod"]["actualBom"]["stoneInfo"] = actualbom_data


        # retrieve standardbom information
        logging.info(f"Prepare standardbom")
        try:
            standard_boms_objs = workorder.productionstandardbom_set.all()
        except Exception as e:
            logging.warn(f"No standardbom is found: {e}")
        else:
            standard_boms_data = frontend_serializers.StandardbomSerializer(
                instance=standard_boms_objs, many=True
            ).data
            data["prod"]["stoneInfo"] = standard_boms_data

        # retrieve productionremarkans information
        logging.info(f"Prepare productionremarkans information")
        try:
            productionremarkans_set = (
                workorder.orderrouting.productionremarkans_set.all()
            )
        except Exception as e:
            logging.warn(f"No order router is created: {e}")
        else:
            prodRemark = frontend_serializers.ProductionRemarkAnsSerializer(
                productionremarkans_set, many=True
            ).data
            data["prod"]["prodRemark"] = prodRemark

        # retrieve order routing information
        order_route_detail_objs = order_routing.RouteDetail.objects.filter(
            order_route__workorder=workorder
        ).order_by("seq")
        order_route_detail_data = frontend_serializers.OrderViewRouteDetailSerializer(
            order_route_detail_objs, many=True
        ).data

        routingHistory = []
        logging.info(f"order_route_detail_objs: {order_route_detail_objs}")
        for order_route_detail_obj in order_route_detail_objs:
            history = frontend_lib.get_routing_history(order_route_detail_obj)
            routingHistory.append(history)

        article = {"routing": order_route_detail_data, "routingHistory": routingHistory}

        data["article"] = article

        # General list
        qcfailedreason_serializer = frontend_serializers.QcFailedReasonSerializer(
            order_routing.QcFailedReason.objects.filter(
                role__in=[role], flow=user_account_obj.department.flow
            ),
            many=True,
        )
        data["fail_reason_list"] = qcfailedreason_serializer.data

        prod_remark_serializer = frontend_serializers.ProductionRemarkSerializer(
            order_routing.ProductionRemark.objects.all(), many=True
        )
        data["prod_remark_list"] = prod_remark_serializer.data
        
        if settings.DJANGO_STATIC_ORDER_IMG:
            logging.info("Display static image")
            parent_path="images/fr_tsl/60979_color"
            stone_parent_path="images/fr_tsl/60979_stone"
            black_parent_path="images/fr_tsl/60979_black"
            data["colorImgs"] = [settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979A.JPG",
                        settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979B.JPG",
                        settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979C.JPG",
                        settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979D.JPG",
                        settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979E.JPG",
                        settings.DJANGO_HOST + settings.STATIC_URL + parent_path+"/60979F.JPG",
                        ] 
            data["stoneImgs"] = { 
                    "orderNo": "700000003233", 
                    "imgData": [ 
                    { 
                        "imgUrl": settings.DJANGO_HOST + settings.STATIC_URL + stone_parent_path+"/60979.jpeg", 
                        "fileName": "60979.JPG (test)"
                    }, 
                    { 
                        "imgUrl": settings.DJANGO_HOST + settings.STATIC_URL + stone_parent_path+"/60979.jpeg", 
                        "fileName": "60979.jpg (test)" 
                    }
                    ] 
                }
            data["design"]["blackPicUrl"]= settings.DJANGO_HOST + settings.STATIC_URL + black_parent_path + "/60979.jpg",
        else:
            stoneImgs = frontend_orderview.parse_stoneImgs(workorder.order)
            colorImgs = frontend_orderview.parse_colorImgs(workorder.order)
            
            data["colorImgs"] = colorImgs
            data["stoneImgs"] = stoneImgs

        # check order action record for the user
        last_order_flow_record_obj = common.get_last_order_flow_record(workorder)
        data["status"] = frontend_orderview.parse_orderview_status(
            last_order_flow_record_obj, workorder
        )

        data["status"]["holder_name"] = frontend_orderview.update_center_sender_name(data["status"], data["article"]["routing"])

        logging.info(f"Get record for order")
        data["record"], last_record_obj_by_role, last_record_obj = frontend_orderview.parse_orderview_data(
            workorder, user_account_obj
        )

        logging.info(f"Check user permission")
        # last_record_obj = common.get_last_order_flow_record(workorder)
        data["editable"], _ = common.check_user_can_change_status(
            workorder, last_record_obj, user_account_obj
        )

        # set worker restart flow
        logging.info(f"Set worker restart flow")
        data["record"] = frontend_orderview.set_worker_restart_flag(data["editable"] , data["record"] )
        
        # logging.info(f"{last_record_obj_by_role=}")
        # logging.info(f"{last_record_obj=}")
        # data["qc_reset"] = common.check_allow_qc_reset(
        #     last_record_obj_by_role, user_account_obj, last_record_obj
        # )

        # print("last_record_obj_by_role", last_record_obj_by_role)

        # routing table of order
        stone_mount_serialzer = frontend_serializers.StoneMountSettingSerializer(
            routes.StoneMountSetting.objects.all(), many=True
        )
        flow_serialzer = frontend_serializers.FlowSerializer(
            users.Flow.objects.all(), many=True
        )
        difficulty_serialzer = frontend_serializers.DifficultySerializer(
            routes.Difficulty.objects.all(), many=True
        )
        data["routing_table"] = {
            "options": {
                "stone_mount_list": stone_mount_serialzer.data,
                "flow": flow_serialzer.data,
                "difficulty": difficulty_serialzer.data,
            }
        }

        display_config_data = frontend_orderview.parse_display_config(role, user_account_obj)
        data["display_config"]=display_config_data



        logging.info(f"return data: {data}")

        message = "Success"
        return frontend_response(status.HTTP_200_OK, message, data)

    # update production remark for order
    @action(detail=True, methods=["post"], url_path="update_production_remark")
    def update_production_remark(self, request, pk=None):
        order = pk
        data = {"prodRemark": []}
        message = "Success"
        prodRemarkAns = request.data["prodRemark"]

        order_routing_obj = order_routing.OrderRouting.objects.get(
            workorder__order=order
        )
        for ans in prodRemarkAns:
            (
                prod_remark_ans_obj,
                _created,
            ) = order_routing.ProductionRemarkAns.objects.update_or_create(
                prod_remark=order_routing.ProductionRemark.objects.get(
                    pk=ans["config_pk"]
                ),
                order_routing=order_routing_obj,
                defaults={"production_remark_ans": ans["ans"]},
            )
            data["prodRemark"].append(
                {
                    "config_pk": prod_remark_ans_obj.pk,
                    "description": prod_remark_ans_obj.prod_remark.remark,
                    "type": prod_remark_ans_obj.prod_remark.type,
                    "ans": prod_remark_ans_obj.production_remark_ans,
                }
            )

        return frontend_response(status.HTTP_200_OK, message, data)

    @action(detail=True, methods=["get"], url_path="get_actual_bom")
    def get_actual_bom(self, request, pk=None):
        logging.error(f"Refresh actual bom for order view")
        order = pk
        data = {"actualBom": []}
        message = "Success"
        workorder = self.get_object()
        try:
            message, actualbom_data=frontend_orderview.get_actual_bom_fr_fgr(workorder.order, workorder.source)
            data["actualBom"] = actualbom_data
        except Exception as e:
            logging.error(f"Exception to query actual bom from FGR: {e}")

        return frontend_response(status.HTTP_200_OK, message, data)

    @action(detail=False, methods=["get"], url_path="get_black_pic_img")
    def get_black_pic_img(self, request):
        """
            图片代理(不需要权限)
            例：
                请求url = http://127.0.0.1:8000/api/frontend/OrderView/get_black_pic_url/?image_url=http://xxx.xxx.xxx/img.jpg
        """
        if (img_url := request.GET.get("image_url")) != "null":
            res = requests.get(img_url)
            response = HttpResponse(content_type='image/jpeg')
            response['Content-Disposition'] = 'attachment; filename="img.jpg"'
            response.write(res.content)
            return response
        return frontend_response(status.HTTP_400_BAD_REQUEST, None)

class OrderRouteView(ModelViewSet):
    queryset = order_routing.RouteDetail.objects.all()
    serializer_class = frontend_serializers.UpdateRouteDetailSerializer

    http_method_names = ["post"]
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    @action(detail=False, methods=["post"], url_path="update_order_routing")
    def update_order_routing(self, request, pk=None, *args, **kwargs):
        message = "False"
        data = {}
        routing_data = request.data.get("routing", [])

        # 进行中的flow不能修改
        order_no = request.data.get("order_no")
        try:
            workorder = workorders.Detail.objects.get(order=order_no)
        except workorders.Detail.DoesNotExist:
            return frontend_response(status.HTTP_200_OK, "订单不可用", None, "Fail")
        order_route_detail_objs = order_routing.RouteDetail.objects.filter(
            order_route__workorder=workorder , status=2,
        ) 
        order_route_detail_data_queryset = frontend_serializers.OrderRouteCheckFlowChangeSerializer(
            order_route_detail_objs, many=True
        ).data 
        for order_route_detail_data in order_route_detail_data_queryset: 
            add_flow_index = 0
            now_flow_index = 0
            now_flow = order_route_detail_data.get("flow")
            now_flow_pk = order_route_detail_data.get("pk")
            for index, route in enumerate(routing_data): 
                upload_route_pk = route.get("pk")
                upload_flow = route.get("flow")
                if upload_route_pk == now_flow_pk:
                    now_flow_index = index

                if upload_route_pk == None:
                    add_flow_index = index

                if add_flow_index < now_flow_index:
                    return frontend_response(status.HTTP_200_OK, "禁止在进行中的Flow前面插入") 

                if (upload_route_pk == now_flow_pk) and (upload_flow != now_flow):
                    return frontend_response(status.HTTP_200_OK,"禁止修改正在进行中的flow流程",None,"Fail")

        if not routing_data:
            logging.info(f"routing_data is {routing_data}")
            logging.info(f"Delete all routing table in OPEN status")
        else:
            logging.info(f"Update routing_data: {routing_data}")
      
            order_route_obj = order_routing.OrderRouting.objects.get(
                pk=routing_data[0]["order_route"]
            )
            last_seq = len(routing_data)
            logging.info(
                f"last seq is {last_seq} for order {order_route_obj}. Delete the order routeing with seq larger than {last_seq}"
            )
            common.delete_order_routing_after_seqx(last_seq, order_route_obj)
            
            def delete_duplicates_flow(seq, order_route):
                """删除seq重复的flow, 必须要是1, 2, 3, 4, 5 ...增加, 防止出现11, 22, 3, 4, 5 ..."""

                seq_flow_queryset = self.queryset.filter(seq=seq, order_route=order_route)
                if count := seq_flow_queryset.count():
                    # 同一个seq不能有多个flow(需要进行删除)
                    instance = seq_flow_queryset.first()
                    if count > 1:
                        seq_flow_id_list = seq_flow_queryset.values_list("id", flat=True)
                        # 查询出被引用的(这些删除会报错)
                        record_id_list = set(order_routing.Record.objects.filter(route_detail_id__in=seq_flow_id_list).values_list("route_detail_id", flat=True))
                        actual_weight_id_list = set(order_routing.ActualWeight.objects.filter(route_detail_id__in=seq_flow_id_list).values_list("route_detail_id", flat=True))

                        # 被应用的flow
                        use_seq_flow_id_list = record_id_list.union(actual_weight_id_list)

                        # 删除没有被引用的
                        delete_flow_id = set(seq_flow_id_list) - use_seq_flow_id_list
                        self.queryset.filter(id__in=delete_flow_id).delete()
                        instance = seq_flow_queryset.filter(id__in=use_seq_flow_id_list).first()
                    return instance

            for routing in routing_data:
                pk = routing.get("pk", None)
                seq = routing.get("seq", None)
                order_route = routing.get("order_route", None)
                instance = None
                if instance := delete_duplicates_flow(seq, order_route):
                    serializer = self.get_serializer(instance, data=routing) # 修改
                else:
                    serializer = self.get_serializer(data=routing) # 创建

                if serializer.is_valid():
                    if instance:
                        if instance.status == 1:
                            logging.info(
                                f"Update order routing for {instance}: {routing}"
                            )
                            update_instance = serializer.save()
                            record_queryest = update_instance.record_set.all().order_by("pk")
                            if record_queryest.exists():
                                record_obj = record_queryest.first()
                                common.check_route_detail_flow_record(record_obj, update_instance.flow)
                            message = "Success"
                        else:
                            logging.warn(
                                f"Fail to update ordering routing {instance} as it is not in OPEN status: {instance.status}"
                            )
                    else:
                        # pk=serializer.validated_data.pop('pk')
                        logging.info(
                            f"Create new order routing: {serializer.validated_data}"
                        )
                        serializer.create(serializer.validated_data)
                        message = "Success"

                else:
                    message = "Fail"
                    logging.error(f"{serializer.errors} for RouteDetail pk {pk}")

                # Check the last seq
                seq = serializer.data["seq"]
                last_seq = seq if seq > last_seq else last_seq

            # if instance:
            #     order_route_obj = instance.order_route
            # else:
            #     order_route_obj = order_routing.OrderRouting.objects.get(
            #         pk=serializer.data["order_route"]
            #     )
            # logging.info(
            #     f"last seq is {last_seq} for order {order_route_obj}. Delete the order routeing with seq larger than {last_seq}"
            # )
            # common.delete_order_routing_after_seqx(last_seq, order_route_obj)
        return frontend_response(status.HTTP_200_OK, message, data)


# For mass scan page to get the order on hold by the user account
# Mass Scan for worker and QC
class OrderOnHoldView(ReadOnlyModelViewSet):
    queryset = order_routing.Record.objects.none()
    serializer_class = frontend_serializers.RecordSerializer

    http_method_names = ["get", "post"]
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    # The main page of mass scan to check order on hand
    def retrieve(self, request, pk):
        message = "Success"
        data = {"record": []}
        account_pk = pk

        user_account_obj = users.Account.objects.get(pk=account_pk)
        role = user_account_obj.role
        flow = user_account_obj.department.flow

        logging.info(f"Search all on hold orders by user {user_account_obj}")

        in_progress_order_objs = order_routing.RouteDetail.objects.filter(
            status=2, flow=flow
        )
        if in_progress_order_objs.exists():
            logging.info(f"User is role {role.name}")
            order_route_objs = order_routing.OrderRouting.objects.filter(
                holder=user_account_obj
            )
            on_hold_record_objs = order_routing.Record.objects.filter(
                route_detail__in=in_progress_order_objs,
                route_detail__order_route__in=order_route_objs,
            )

            # get the last record only
            # on_hold_record_objs = on_hold_record_objs.order_by('route_detail__order_route__workorder__order', '-pk').distinct('route_detail__order_route__workorder__order')

            data["record"] = frontend_lib.parse_orderonhold_data(on_hold_record_objs)

        else:
            logging.info(f"No orders are in progress for flow {flow}")

        # General list
        # qcfailedreason_serializer=frontend_serializers.QcFailedReasonSerializer(order_routing.QcFailedReason.objects.all(), many=True)
        # data["fail_reason_list"]=qcfailedreason_serializer.data

        # prod_remark_serializer=frontend_serializers.ProductionRemarkSerializer(order_routing.ProductionRemark.objects.all(), many=True)
        # data["prod_remark_list"]=prod_remark_serializer.data

        return frontend_response(status.HTTP_200_OK, message, data)

    # Search order and start the order in mass scan
    @action(methods=["post"], detail=True, url_path="search_order")
    def search_order(self, request, pk=None):
        # TODO only allow user to start

        orders = request.data["orders"]
        source = request.data["source"]
        print("orders: ", orders)
        data = {
            "allowed_list": [],
            "no_perm_list": [],
            "not_exist_list": [],
            "err_list": [],
        }
        message = "Success"
        account_pk = pk
        for order in orders:
            try:
                detail_obj = workorders.Detail.objects.get(order=order, source=source)
            except workorders.Detail.DoesNotExist:
                logging.info(f"Order {order} not exist")
                data["not_exist_list"].append({"order": order, "data": None})
            else:
                # check wheather the user can change the order status
                if common.check_order_discard(detail_obj):
                    data["not_exist_list"].append({"order": order, "data": None})
                    logging.info(
                        f"Order  {detail_obj} is discarded."
                    )
                else:
                    logging.info(
                        f"Check if user have perm to change status for order {detail_obj}"
                    )
                    user_account_obj = users.Account.objects.get(pk=account_pk)
                    last_order_flow_record_obj = common.get_last_order_flow_record(
                        detail_obj
                    )
                    user_have_perm, error_message = common.check_user_can_change_status(
                        detail_obj, last_order_flow_record_obj, user_account_obj
                    )

                    if user_have_perm:
                        if user_account_obj.role.name == "WORKER":
                            # create Start worker action
                            action_data = {
                                "account_pk": account_pk,
                                "worker_record": order_routing.Record.objects.filter(
                                    route_detail__order_route__workorder__order=order
                                )
                                .last()
                                .worker.pk,
                                "action": 1,
                            }
                            worker_action_serializer = (
                                frontend_serializers.WorkerActionSerializer(
                                    data=action_data
                                )
                            )

                            if worker_action_serializer.is_valid():
                                new_instance = worker_action_serializer.save()
                                data["allowed_list"].append(
                                    {"order": order, "data": new_instance.formatted_time()}
                                )
                            else:
                                message = "Fail"
                                print("Serializer is not valid")
                                logging.error(
                                    f"{worker_action_serializer.errors} for order {orders}."
                                )
                                data["err_list"].append({"order": order, "data": None})

                        elif user_account_obj.role.name == "QC":
                            check_record_obj = last_order_flow_record_obj.qc_check
                            if check_record_obj:
                                qc_data = {
                                    "received_at": timezone.now(),
                                    "account": user_account_obj.pk,
                                }
                                qc_serializer = frontend_serializers.QCActionSerializer(
                                    check_record_obj, data=qc_data, partial=True
                                )
                                if qc_serializer.is_valid():
                                    checkin_obj = qc_serializer.save(
                                        update=check_record_obj, data=qc_data
                                    )
                                    data["allowed_list"].append(
                                        {
                                            "order": order,
                                            "data": checkin_obj.formatted_received_at(),
                                        }
                                    )
                                else:
                                    message = "Fail"
                                    logging.error(
                                        f"Failed to set receive time for QC: {qc_serializer.errors} "
                                    )
                                    data["err_list"].append({"order": order, "data": None})
                            else:
                                logging.warn(f"Fail to find QC record")
                                data["err_list"].append({"order": order, "data": None})

                        elif user_account_obj.role.name == "Teamleader":
                            check_record_obj = last_order_flow_record_obj.leader_check
                            if check_record_obj:
                                qc_data = {
                                    "received_at": timezone.now(),
                                    "account": user_account_obj.pk,
                                }
                                qc_serializer = frontend_serializers.QCActionSerializer(
                                    check_record_obj, data=qc_data, partial=True
                                )
                                if qc_serializer.is_valid():
                                    checkin_obj = qc_serializer.save(
                                        update=check_record_obj, data=qc_data
                                    )
                                    data["allowed_list"].append(
                                        {
                                            "order": order,
                                            "data": checkin_obj.formatted_received_at(),
                                        }
                                    )
                                else:
                                    message = "Fail"
                                    logging.error(
                                        f"Failed to set receive time for Leader: {qc_serializer.errors} "
                                    )
                                    data["err_list"].append({"order": order, "data": None})
                            else:
                                logging.warn(f"Fail to find Teamleader record")
                                data["err_list"].append({"order": order, "data": None})

                        elif user_account_obj.role.name == "StoneQC":
                            check_record_obj = last_order_flow_record_obj.stone_check
                            if check_record_obj:
                                qc_data = {
                                    "received_at": timezone.now(),
                                    "account": user_account_obj.pk,
                                }
                                qc_serializer = frontend_serializers.QCActionSerializer(
                                    check_record_obj, data=qc_data, partial=True
                                )
                                if qc_serializer.is_valid():
                                    checkin_obj = qc_serializer.save(
                                        update=check_record_obj, data=qc_data
                                    )
                                    data["allowed_list"].append(
                                        {
                                            "order": order,
                                            "data": checkin_obj.formatted_received_at(),
                                        }
                                    )
                                else:
                                    message = "Fail"
                                    logging.error(
                                        f"Failed to set receive time for StoneQC: {qc_serializer.errors} "
                                    )
                                    data["err_list"].append({"order": order, "data": None})
                            else:
                                logging.warn(f"Fail to find StoneQC record")
                                data["err_list"].append({"order": order, "data": None})
                    else:
                        data["no_perm_list"].append({"order": order, "data": None, "error_message": error_message})

        return frontend_response(status.HTTP_200_OK, message, data)


# Worker action to start/pause/complete the order
class WorkerActionView(ModelViewSet):
    queryset = order_routing.WorkerActionRecord.objects.none()
    serializer_class = frontend_serializers.WorkerActionSerializer

    http_method_names = ["post"]
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    def create(self, request, *args, **kwargs):
        message = "Success"
        data = {}

        orders = request.data["orders"]
        account_pk = request.data["account_pk"]
        action = request.data["action"]

        choices = order_routing.WorkerActionRecord.action.field.choices
        for value, label in choices:
            if label == action:
                action_int = value

        logging.info(f"request.data: {request.data}")
        for order in orders:
            record_obj = order_routing.Record.objects.filter(
                route_detail__order_route__workorder__order=order
            ).last()
            logging.info(f"Get Record for order {order}: {record_obj}")

        action_data = [
            {
                "account_pk": account_pk,
                "worker_record": order_routing.Record.objects.filter(
                    route_detail__order_route__workorder__order=order
                )
                .last()
                .worker.pk,
                "action": action_int,
            }
            for order in orders
        ]

        logging.info(f"Update worker action record: {action_data}")
        serializer = self.serializer_class(data=action_data, many=True)
        if serializer.is_valid():
            new_instance = serializer.save()
            # Get all saved instances
            saved_instances = serializer.instance
            data["orders"] = [
                {
                    "order": order,
                    "action": instance.get_action_display() if instance else None,
                    "time": instance.formatted_time() if instance else None,
                }
                for order, instance in zip(orders, saved_instances)
            ]

        else:
            message = "Fail"
            logging.error(f"{serializer.errors} for order {orders}.")

        logging.info(f"WorkerActionView create data: {data}")

        return frontend_response(status.HTTP_200_OK, message, data)

class QCActionView(ModelViewSet):

    """
    QC审核点击开始触发【
    {
    "failed_details": [
        {
        "reason": QcFailedReason_pk,
        "quantity": <BOOL> 0 - False , 1 - True / <INT>
        }
    ],
    "received_at": "start qc flow time",
    "check_at": "submit qc result time",
    "failed": true - fail / false - pass,
    "remark": "string",
    "account": account_pk
    }

    will only update the fields if exists
    """

    queryset = order_routing.CheckRecord.objects.all()
    serializer_class = frontend_serializers.QCActionSerializer

    http_method_names = ["put"]
    permission_classes = [IsAuthenticated]
    authentication_classes = [JWTAuthentication]

    def get_object(self):
        queryset = self.filter_queryset(self.get_queryset())
        obj = queryset.get(pk=self.kwargs["pk"])
        return obj

    def update(self, request, pk, *args, **kwargs):
        message = "Success"
        data = {}
        check_record_obj = self.get_object()

        # frontend生成的时间晚8小时, backend添加来恢复成正常时间
        # if received_at := request.data.get("received_at", None):
        #     if isinstance(received_at, str):
        #         check_at_time = timezone.datetime.fromisoformat(received_at[:-1])
        #         check_at_time = check_at_time + timedelta(hours=8)
        #         request.data["received_at"] = check_at_time.strftime('%Y-%m-%d %H:%M:%S')   

        serializer = self.get_serializer(
            check_record_obj, data=request.data, partial=True
        )

        if serializer.is_valid():
            account_obj = serializer.validated_data.get("account")
        else:
            message = "Fail"
            logging.error(
                f"QCActionSerializer is invalid for CheckRecord {pk}: {serializer.errors} "
            )
            return frontend_response(status.HTTP_200_OK, message, data)

        detail_obj = frontend_lib.filter_detail_obj_by_check_record(check_record_obj)
        last_order_flow_record_obj = common.get_last_order_flow_record(detail_obj)
        editable, error_message = common.check_user_can_change_status(
            detail_obj, last_order_flow_record_obj, account_obj
        )
        if not editable:
            logging.info(
                f"{account_obj} is not allowed to change status of the order {detail_obj}"
            )
            message = f"{account_obj.django_user.cnName} is not allowed to change status of the order {detail_obj}"
            return frontend_response(status.HTTP_200_OK, message, data)

        if common.check_qc_record_editable(check_record_obj):
            logging.info(f"QCActionSerializer is valid for CheckRecord {pk}.")
            # check if failed reason is selected
            qc_valid = serializer.check_fail_reason()
            logging.info(f"{qc_valid=}")
            if qc_valid:
                self.perform_update(serializer)
                check_record_obj.refresh_from_db()  # refresh the instance from the database to get the latest version
                if not check_record_obj.failed:
                    common.update_route_detail_status(check_record_obj)
            else:
                logging.info(f"QC result is not valid. Please select reason.")
                message = "Fail"

        else:
            logging.info(
                f"{check_record_obj} is already submitted. Don't update result"
            )

        return frontend_response(status.HTTP_200_OK, message, data)

    @action(methods=["put"], detail=True, url_path="reset_qc_result")
    def reset_qc_result(self, request, pk=None):
        message = "Success"
        data = {}
        check_record_obj = self.get_object()
        logging.info(f"Reset qc result for {check_record_obj}")
        if not common.check_qc_record_editable(check_record_obj):
            logging.info("Reset qc result")

            old_failed_details = check_record_obj.failed_details.all()
            old_failed_details.delete()

            check_record_obj.check_at = None
            check_record_obj.failed = None
            check_record_obj.remark = None
            # check_record_obj.work_count -= 1
            check_record_obj.save()

            # delete the new empty created record
            # case 1: if it is fail and not last step, new record is created for current flow
            # case 2: if it is pass and last step, new record is created for next flow
            # check any new record for current flow and next step and with larger pk than self
            frontend_lib.delete_new_created_record(check_record_obj)

        return frontend_response(status.HTTP_200_OK, message, data)


#  Original
class MissingParamException(Exception):
    """Missing Required Parameter!"""

    pass
